1 module hip.ai.pathfinding; 2 version(Test): 3 import hip.util.data_structures; 4 5 private struct AStarNode 6 { 7 AStarNode* previous; 8 int id; 9 int g, h; 10 int f(){return g+h;} 11 } 12 13 pragma(inline, true) 14 int manhattanHeuristic(int posX, int posY, int targetX, int targetY) 15 { 16 int dx = targetX - posX; 17 int dy = targetY - posY; 18 return (dx < 0 ? -dx : dx) + (dy < 0 ? -dy : dy); 19 } 20 21 struct AStarResult(T) 22 { 23 bool isPossible; 24 T[] path; 25 } 26 27 AStarResult!T AStar2D_4Way(T, Q)(ref T[] map, uint startX, uint startY, int columns, uint targetX, uint targetY, Q walls) 28 { 29 import hip.util.array; 30 uint start = startY*columns+startX; 31 uint target = targetY*columns+targetX; 32 AStarResult!T ret; 33 34 AStarNode[] open = [AStarNode(null, start, 0, manhattanHeuristic(startX, startY, targetX, targetY))]; 35 AStarNode[] closed; 36 37 pragma(inline, true) enum append = (AStarNode* prev, T num) 38 { 39 import std.traits:isArray; 40 static if(is(typeof(walls) == typeof(null))){} 41 else static if(isArray!Q) 42 { 43 for(ulong i = 0; i < walls.length; i++) 44 if(map[num] == walls[i]) 45 return; 46 } 47 else 48 { 49 if(map[num] == walls) 50 return; 51 } 52 if(!closed.contains!"id"(num)) 53 { 54 int ind = open.indexOf!"id"(num); 55 if(ind != -1) 56 { 57 if(prev.g+1 < open[ind].g) 58 { 59 open[ind].g = prev.g+1; 60 open[ind].previous = prev; 61 } 62 } 63 else if(prev != null) 64 open~=AStarNode(prev, num, prev.g+1, manhattanHeuristic(num%columns, num/columns, targetX, targetY)); 65 66 } 67 68 }; 69 int current; 70 AStarNode* node; 71 while(!open.isEmpty) 72 { 73 ulong lowestF = 0; 74 75 for(ulong i =0; i < open.length; i++) 76 if(open[i].f < open[lowestF].f) 77 lowestF = i; 78 79 closed~=open[lowestF]; 80 node = &open[lowestF]; 81 current = node.id; 82 83 if(open[lowestF].id == target) 84 { 85 ret.isPossible = true; 86 break; 87 } 88 int currentColumn = current%columns; 89 //Get the adjacents to the current> 90 91 92 //Neighbors part 93 94 //Up -> Check if there is a row up 95 if((current - columns) >= 0) //Don't access out of bounds 96 append(node, cast(T)(current-columns)); 97 //Right -> Check if it does not go a row down 98 if((current + 1)%columns > currentColumn) 99 append(node, cast(T)(current+1)); 100 //Down -> Check if there is a row down 101 if(current + columns < map.length) //Don't access out of bounds 102 append(node, cast(T)(current+columns)); 103 //Left -> Check if it does not go a row up 104 if(current-1 >= 0 && (current - 1)%columns < currentColumn) 105 { 106 append(node, cast(T)(current-1)); 107 } 108 109 open.remove(*node); 110 111 } 112 113 while(node.previous) 114 { 115 ret.path~= cast(T)node.id; 116 node = node.previous; 117 } 118 ret.path~= cast(T)node.id; 119 return ret; 120 }